package services;

import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;

import org.codehaus.jackson.JsonNode;

import collectors.calendar.models.Event;
import collectors.email.models.GmailEmail;
import collectors.file.models.FileInfo;
import collectors.people.models.PeopleUser;
import collectors.people.models.PeopleUser.FacebookData;
import play.libs.F.Promise;
import util.AppState;

public abstract class CollectorService {

	public enum Services {FILE, EMAIL, CALENDAR, PEOPLE}
	
	public static Promise<List<Event>> searchEvents(Long calUserId, String query) {
		return getService(Services.CALENDAR).searchEventsImpl(calUserId, query);
	}
	
	public static Promise<List<Event>> getEventDetails(Long calUserId, String eventId) {
		return getService(Services.CALENDAR).getEventDetailsImpl(calUserId, eventId);
	}
	
	public static Promise<List<GmailEmail>> searchEmails(Long gmailUserId, String query, int max) {
		return getService(Services.EMAIL).searchEmailsImpl(gmailUserId, query, max);
	}
	
	public static Promise<List<FileInfo>> getMetadata(Long fileUserId, String path) {
		return getService(Services.FILE).getMetadataImpl(fileUserId, path);
	}
	
	public static Promise<List<FileInfo>> searchFiles(Long fileUserId, String query, String path) {
		return getService(Services.FILE).searchFilesImpl(fileUserId, query, path);
	}
	
	public static Promise<InputStream> getFile(Long fileUserId, String path) {
		return getService(Services.FILE).getFileImpl(fileUserId, path);
	}
	
	public static Promise<JsonNode> getPeopleUserData(Long peopleUserId) {
		return getService(Services.PEOPLE).getPeopleUserDataImpl(peopleUserId);
	}
	
	public static Promise<List<PeopleUser.FacebookData>> searchPeople(Long peopleUserId, String query) {
 		return getService(Services.CALENDAR).searchPeopleImpl(peopleUserId, query);
	}
	
	/**
	 * 
	 * @param toCreate
	 * @return list of ids of new users. The order is the same as the parameter
	 *         array.
	 */
	
	public static Promise<List<Long>> createUsers(Services... toCreate) {
		List<Promise<? extends Long>> ids = new LinkedList<Promise<? extends Long>>();
		for (Services service : toCreate) {
			Promise<Long> prom = null;
			switch(service){
			case CALENDAR:
				prom = getService(Services.CALENDAR).createCalendarUser();
				break;
			case EMAIL:
				prom = getService(Services.EMAIL).createEmailUser();
				break;
			case FILE:
				prom = getService(Services.FILE).createFileUser();
				break;
			case PEOPLE:
				prom = getService(Services.PEOPLE).createPeopleUser();
				break;
			}
			ids.add(prom);
		}
		return Promise.sequence(ids);
	}
	
	public static String getBaseUrl(Services service) {
		return getService(service).getBaseUrlImpl(service);
	}
	
	private static CollectorService getService(Services service) {
		CollectorService result;
		AppState state = AppState.get();
		boolean remote = false;
		
		switch(service) {
		case FILE:
			remote = state.dropboxRemoteCall == AppState.OpStatus.ENABLED;
			break;
		case EMAIL:
			remote = state.gmailRemoteCall == AppState.OpStatus.ENABLED;
			break;
		case CALENDAR:
			remote = state.calendarRemoteCall == AppState.OpStatus.ENABLED;
			break;
		case PEOPLE:
			remote = state.facebookRemoteCall == AppState.OpStatus.ENABLED;
			break;
		}
		
		result = remote ? RemoteCollectorService.get() : LocalCollectorService.get();
		return result;
	}

	
	abstract Promise<List<Event>> searchEventsImpl(Long calUserId, String query);
	
	abstract Promise<List<Event>> getEventDetailsImpl(Long calUserId, String eventId);
	
	abstract Promise<List<GmailEmail>> searchEmailsImpl(Long gmailUserId, String query, int max);
	
	abstract Promise<List<FileInfo>> getMetadataImpl(Long fileUserId, String path);
	
	abstract Promise<List<FileInfo>> searchFilesImpl(Long fileUserId, String query, String path);
	
	abstract Promise<InputStream> getFileImpl(Long fileUserId, String path);
	
	abstract Promise<JsonNode> getPeopleUserDataImpl(Long peopleUserId);
	
	abstract Promise<List<FacebookData>> searchPeopleImpl(Long peopleUserId, String query);

	abstract String getBaseUrlImpl(Services service);

	abstract Promise<Long> createPeopleUser();
	abstract Promise<Long> createFileUser();
	abstract Promise<Long> createEmailUser();
	abstract Promise<Long> createCalendarUser();
	
}
